package org.adream.account.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.adream.account.model.ResultModel;
import org.adream.account.service.ADreamServiceException;
import org.adream.account.service.OAuthService;
import org.adream.account.service.OAuthService.OAUTHTYPE;
import org.adream.account.service.UserService;
import org.adream.account.util.Constant;
import org.adream.account.util.HttpClientUtil;
import org.adream.account.util.PageUtil;
import org.adream.account.util.StateValidateUtil;
import org.adream.account.util.UserUtil;
import org.adream.account.util.Utils;
import org.adream.account.util.WeixinUtil;
import org.adream.account.util.WeixinUtil.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 第三方绑定 解绑
 * 
 * @author chenhaoyu
 *
 */
@Controller
@RequestMapping(value = "/oauth/")
public class OAuthController {
	
	private final static Logger logger = LoggerFactory.getLogger(OAuthController.class);
	
	@Autowired
	private OAuthService oauthService;
	
	@Autowired
	private UserService userService;
	
	//微信参数
	@Value("${wx.appid}")
	private String wx_appid;
	
	@Value("${wx.secret}")
	private String wx_secret;
	
	@Value("${wx.redirect.url}")
	private String wx_redirect_uri;
	
	@Value("${wx.response.type}")
	private String wx_response_type; //固定字符
	
	@Value("${wx.scope}")
	private String wx_scope; //网页部分固定字符
	
	@Value("${wx.grant.type}")
	private String wx_grant_type;
	
	//微信公众号参数
	@Value("${wx.app.appid}")
	private String wx_app_appid;
	
	@Value("${wx.app.secret}")
	private String wx_app_secret;
	
	@Value("${wx.app.redirect.url}")
	private String wx_app_redirect_url;
	
	@Value("${wx.app.scope}")
	private String wx_app_scope;
	
	@Value("${scFire.redirectUrl}")
	private String scfireRedirectUrl;	//火堆重定向页面
	
	//qq参数
	@Value("${qq.appid}")
	private String qq_appid;
			
	@Value("${qq.appkey}")
	private String qq_app_key;
			
	@Value("${qq.redirect.url}")
	private String qq_redirect_url;
	
	/**
	 * 微信扫码 绑定回调
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "wxcallback")
	public ModelAndView wxCallback(HttpServletRequest request, HttpServletResponse response) {
		logger.debug("微信扫码 绑定回调");
		//先做state验证 防止csrf
		String state = null;
		String uid =  null;
		try {
			state = StateValidateUtil.getDecodeState(request.getParameter("state"));
			uid = state.split("_")[1];
		} catch (ADreamServiceException e) {
			logger.warn("绑定失败:" + e.getMessage());
			return PageUtil.errorPage("绑定失败:" + e.getMessage());
		}
		
		String code = request.getParameter("code");
		if (StringUtils.isEmpty(code)) {
			logger.warn("绑定失败:code值为空:(");
			return PageUtil.errorPage("绑定失败:参数有误");
		}
		String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ wx_appid
				+ "&secret=" + wx_secret
				+ "&code=" + code
				+ "&grant_type="+ wx_grant_type;
		
		Token token = null;
		try {
			token = WeixinUtil.getToken(url);
			if(token == null) {
				logger.warn("绑定失败:参数有误");
				return PageUtil.errorPage("绑定失败:参数有误");
			}
		} catch (Exception e) {
			logger.warn("绑定失败:" + e.getMessage());
			return PageUtil.errorPage("绑定失败:" + e.getMessage());
		}
		
		String unionid = token.getUnionid();
		//判断该微信是否已绑定
		//若该微信已绑定,直接到错误页面
		if(!userService.isValidUnionid(unionid)) {
			logger.warn("绑定失败:unionid:" + unionid + "已存在");
			return PageUtil.errorPage("绑定失败:该微信已绑定");
		}
		String access_token = token.getAccessToken();
		String openid = token.getOpenId();
		String nickName = "";
		
		if (state.startsWith(StateValidateUtil.TYPE_BIND)) {
			//走绑定逻辑
			//把 openid + unionid  写入数据库 返回一个绑定成功页面
			logger.info("openid:" + openid + ",unionid:" + unionid + ",uid:" + uid + ",nickName:" + nickName);
			try {
				String getInfoUrl =  "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid;
				//解决微信中文昵称乱码
				JSONObject user_info = JSON.parseObject(new String(HttpClientUtil.HttpGet(getInfoUrl).getBytes("ISO-8859-1"),"UTF-8"));
				if(user_info != null && user_info.containsKey("nickname")) {
					nickName = user_info.getString("nickname");
				}
				oauthService.bind(OAUTHTYPE.WECHAT, uid, nickName, unionid,openid + "_" + wx_appid);
			} catch (ADreamServiceException e) {
				logger.warn("绑定失败:" + e.getMessage());
				return PageUtil.errorPage("绑定失败:" + e.getMessage());
			} catch (UnsupportedEncodingException e) {
				logger.warn("绑定失败:" + e.getMessage());
				return PageUtil.errorPage("绑定失败:" + e.getMessage());
			} 
			
			//获取跳转过来的系统名称
			String system = request.getParameter(Constant.SYSTEM);
			if(!StringUtils.isEmpty(system) && Constant.SYSTEM_SCFIRE.equals(system.toLowerCase())) {
				//火堆系统
				return new ModelAndView("redirect:" + scfireRedirectUrl);
			}
			return PageUtil.successPage("绑定成功");					
		} else {
			return PageUtil.errorPage("绑定失败:参数有误");
		}
	}
	
	/**
	 * 移动端 绑定
	 * @param type	bind/login
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "wxapp/{type}")
	public void phoneWx(@PathVariable("type") String type,
			HttpServletRequest request,HttpServletResponse response) {
		logger.debug("移动端 绑定");
		if(StringUtils.isEmpty(type)) {
			logger.warn("微信绑定失败,请求参数为空:)");
			return;
		}
		try {
			String url = null;
			String uid = UserUtil.getUidByRequest(request);
			if(StateValidateUtil.TYPE_BIND.equals(type)) {
				if(StringUtils.isEmpty(uid)) {
					logger.warn("微信绑定失败,请求参数uid为空:)");
					return;
				}
				url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + wx_app_appid
						+ "&redirect_uri=" + URLEncoder.encode(wx_app_redirect_url, "utf-8") 
						+ "&response_type=" + wx_response_type 
						+ "&scope=" + wx_app_scope 
						+ "&state=" + StateValidateUtil.getBindState(uid)
						+ "&connect_redirect=1"
						+ "#wechat_redirect";
			} else {
				logger.warn("微信绑定失败,请求参数有误:(");
				return;
			}
			response.sendRedirect(url);
			return;
		} catch (UnsupportedEncodingException e) {
			logger.warn("移动端绑定失败,不支持的编码格式:(");
		} catch (IOException e) {
			logger.warn("移动端绑定失败,io异常:)");
		}
	}
	
	/**
	 * 移动端 微信公众号绑定 回调
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "wxappcallback")
	public ModelAndView wxAPPCallback(HttpServletRequest request, HttpServletResponse response) {
		logger.debug("移动端微信公众号回调");
		//先做state验证 防止csrf
		String state = null;
		String uid =  null;
		try {
			state = StateValidateUtil.getDecodeState(request.getParameter("state"));
			uid = state.split("_")[1];
		} catch (ADreamServiceException e) {
			logger.warn("绑定失败:" + e.getMessage());
			return PageUtil.appErrorPage("绑定失败:" + e.getMessage());
		}
		
		String code = request.getParameter("code");
		if (StringUtils.isEmpty(code)) {
			logger.warn("绑定失败:code值为空:(");
			//用户取消授权 去一个取消操作的页面
			return PageUtil.appErrorPage("绑定失败:参数有误");
		}
		String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ wx_app_appid
				+ "&secret=" + wx_app_secret
				+ "&code=" + code
				+ "&grant_type=" + wx_grant_type;
		
		Token token = null;
		try {
			token = WeixinUtil.getToken(url);
			if(token == null) {
				logger.warn("绑定失败:参数有误");
				return PageUtil.appErrorPage("绑定失败:参数有误");
			}
		} catch (Exception e) {
			logger.warn("绑定失败:" + e.getMessage());
			return PageUtil.appErrorPage("绑定失败:" + e.getMessage());
		}
		String unionid = token.getUnionid();
		//判断该微信是否已绑定
		//若该微信已绑定,直接到错误页面
		if(!userService.isValidUnionid(unionid)) {
			logger.warn("绑定失败,unionid:" + unionid + "已存在");
			return PageUtil.appErrorPage("绑定失败:该微信已绑定");
		}
		String access_token = token.getAccessToken();
		String openid = token.getOpenId();
		String nickName = "";
				
		if (state.startsWith(StateValidateUtil.TYPE_BIND)) {
			//走绑定逻辑
			//把 openid + unionid  写入数据库 返回一个绑定成功页面
			logger.info(openid + "," + unionid + "," + uid);
			try {
				String getInfoUrl =  "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid;
				JSONObject user_info = JSON.parseObject(new String(HttpClientUtil.HttpGet(getInfoUrl).getBytes("ISO-8859-1"),"UTF-8"));
				if(user_info != null && user_info.containsKey("nickname")) {
					nickName = user_info.getString("nickname");
				}
				oauthService.bind(OAUTHTYPE.WECHAT, uid, nickName, unionid,openid + "_" + wx_app_appid);
			} catch (ADreamServiceException e) {
				logger.warn("绑定失败:" + e.getMessage());
				return PageUtil.appErrorPage("绑定失败:" + e.getMessage());
			} catch (UnsupportedEncodingException e) {
				logger.warn("绑定失败:" + e.getMessage());
				return PageUtil.appErrorPage("绑定失败:" + e.getMessage());
			} 
			//获取跳转过来的系统名称
			String system = request.getParameter(Constant.SYSTEM);
			if(!StringUtils.isEmpty(system) && Constant.SYSTEM_SCFIRE.equals(system.toLowerCase())) {
				//重定向到火堆系统
				return new ModelAndView("redirect:" + scfireRedirectUrl);
			}
			return PageUtil.successPage("绑定成功");					
		} else {
			return PageUtil.errorPage("绑定失败:参数有误");
		}
	}
	
	/**
	 * qq 绑定
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "qq/bind")
	public void qqBind(HttpServletRequest request,HttpServletResponse response) {
		logger.debug("qq绑定");
		String uid = UserUtil.getUidByRequest(request);
		if(StringUtils.isEmpty(uid)) {
			logger.warn("qq绑定失败,uid为空:(");
			return;
		}
		String url;
		try {
			url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" 
						+ "&client_id=" + qq_appid 
						+ "&redirect_uri=" + URLEncoder.encode(qq_redirect_url, "utf-8") 
						+ "&state=" + StateValidateUtil.getBindState(uid);
			response.sendRedirect(url);
		} catch (UnsupportedEncodingException e) {
			logger.warn("qq绑定失败," + e.getMessage());
			return;
		} catch (IOException e) {
			logger.warn("qq绑定失败," + e.getMessage());
			return;
		}
	}
	
	/**
	 * qq绑定回调
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "qqcallback")
	public ModelAndView qqCallback(HttpServletRequest request,HttpServletResponse response) {
		logger.debug("qq绑定回调");
		//先做state验证 防止csrf
		String state = null;
		String uid =  null;
		try {
			state = StateValidateUtil.getDecodeState(request.getParameter("state"));
			uid = state.split("_")[1];
		} catch (ADreamServiceException e) {
			logger.warn("绑定失败:" + e.getMessage());
			return PageUtil.errorPage("绑定失败:" + e.getMessage());
		}
        String code = request.getParameter("code");
        if (StringUtils.isEmpty(code)) {
			logger.warn("qq绑定失败:code值为空:(");
			return PageUtil.errorPage("qq绑定失败:参数有误");
		}       
        //通过Authorization Code获取Access Token
        String getAccessTokenUrl = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code" 
        			+ "&client_id=" + qq_appid
        			+ "&client_secret=" + qq_app_key 
        			+ "&code=" + code 
        			+ "&redirect_uri=" + qq_redirect_url;
        /**
         * 如果成功返回,即可在返回包中获取access token 
         * 		如:access_token=FE04************************CCE2&expires_in=7776000&refresh_token=88E4************************BE14
         * 错误时,会返回code和msg字段,以url参数对的形式返回,value部分会进行url编码（UTF-8）
         */
        String getAccessTokenResult = HttpClientUtil.HttpGet(getAccessTokenUrl);
        JSONObject accessTokenJsonObject = Utils.getJsonObjectByQueueUrl(getAccessTokenResult);
        if(accessTokenJsonObject.containsKey("code")) {
        	logger.warn("获取access token失败,:" + accessTokenJsonObject.getString("msg"));
			return PageUtil.errorPage("绑定失败:" + accessTokenJsonObject.getString("msg"));
        }
        String accessToken = accessTokenJsonObject.getString("access_token");
        String getOpenIdUrl = "https://graph.qq.com/oauth2.0/me?access_token=" + accessToken;
        /**
         * 成功:callback({"client_id":"YOUR_APPID","openid":"YOUR_OPENID"});
         * 失败:返回code和msg字段,以url参数对的形式返回,value部分会进行url编码(UTF-8)
         */
        String getOpenIdResult = HttpClientUtil.HttpGet(getOpenIdUrl);
        if(getOpenIdResult.indexOf("code") != -1) {
        	logger.warn("获取openid失败,:" + Utils.getJsonObjectByQueueUrl(getOpenIdResult).getString("msg"));
        	return PageUtil.errorPage("绑定失败:" + Utils.getJsonObjectByQueueUrl(getOpenIdResult).getString("msg"));
        }
        JSONObject openIdJsonObject = JSONObject.parseObject(getOpenIdResult.substring(getOpenIdResult.indexOf("(") + 1, getOpenIdResult.indexOf(")")));
        String openId = openIdJsonObject.getString("openid");
        try {
			oauthService.bind(OAUTHTYPE.QQ, uid, null, openId, null);
			return PageUtil.successPage("绑定成功");
		} catch (ADreamServiceException e) {
			logger.warn("qq回调失败:" + e.getMessage());
			return PageUtil.errorPage("绑定失败:" + e.getMessage());
		} 
	}
	
	/**
	 * 解绑第三方账号
	 * @param type	第三方账号类型
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "unbind", produces = "application/json;charset=UTF-8", method = RequestMethod.GET)
	@ResponseBody
	public ResultModel<?> unbind(@RequestParam("type")OAUTHTYPE type,HttpServletRequest request) {
		logger.debug("解绑第三方账户");
		String uid = UserUtil.getUidByRequest(request);
		//解绑第三方
		if(StringUtils.isEmpty(type) || StringUtils.isEmpty(uid)) {
			logger.warn("解绑失败,请求参数有误:)");
			return new ResultModel<String>(ResultModel.ERR_PARAM, "解绑失败,请求参数有误", null);
		}
		try {
			oauthService.unbind(type, uid);
			return new ResultModel<String>(ResultModel.SUCCESS, "解绑成功", null);
		} catch (ADreamServiceException e) {
			return new ResultModel<String>(ResultModel.ERR_PARAM, e.getMessage(), null);
		} 
	}
}